package cn.sytton.taffe.web.sys.service.impl;

import cn.sytton.taffe.web.sys.entity.AuthFuncKey;
import cn.sytton.taffe.web.sys.entity.AuthMenuTree;
import cn.sytton.taffe.web.sys.entity.MenuEntity;
import cn.sytton.taffe.web.sys.entity.MenuFuncEntity;
import cn.sytton.taffe.framework.base.service.BaseService;
import cn.sytton.taffe.framework.util.SecurityUtil;
import cn.sytton.taffe.web.sys.mapper.MenuFuncMapper;
import cn.sytton.taffe.web.sys.mapper.MenuMapper;
import cn.sytton.taffe.web.sys.service.IMenuService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 菜单服务层
 *
 * @author skyrock
 */
@Service
@RequiredArgsConstructor
@Transactional(rollbackFor = Exception.class)
public class MenuService extends BaseService<MenuMapper, MenuEntity> implements IMenuService {

    private final MenuFuncMapper menuFuncMapper;

    @Override
    public List<MenuEntity> findMyMenu() {
        List<MenuEntity> tree = new ArrayList<>();

        String userId = SecurityUtil.getUserId();

        //查询自己有权限的末级菜单
        List<MenuEntity> menus = baseMapper.findByUserId(userId);
        //查询自己有权限的末级菜单权限Key
        List<MenuFuncEntity> menuFuncKeys = menuFuncMapper.findByUserId(userId);

        //获取全部的菜单的父级
        Map<String, MenuEntity> parents = findAllParent();

        //向上循环填充父级menu
        Set<String> exists = new HashSet<>();
        int length = menus.size();
        for(int i = 0; i < length; i++) {
            MenuEntity menu = menus.get(i);
            MenuEntity parent = parents.get(menu.getMenuId());
            while (parent != null) {
                if (!exists.contains(parent.getMenuId())) {
                    menus.add(parent);
                }
                exists.add(parent.getMenuId());
                parent = parents.get(parent.getMenuId());
            }
            menu.setFuncKeys(menuFuncKeys
                    .stream()
                    .filter(mf -> mf.getMenuId().equals(menu.getMenuId()))
                    .collect(Collectors.toList())
                    .stream()
                    .map(MenuFuncEntity::getFuncKey)
                    .collect(Collectors.toList()));
        }

        //构建菜单树
        for (MenuEntity menu: menus) {
            if (!StringUtils.hasText(menu.getParentId())) {
                tree.add(menu);
                menu.setChildren(getChildren(menu.getMenuId(), menus));
            }
        }

        return tree.stream().sorted(Comparator.comparing(MenuEntity::getSeq)).collect(Collectors.toList());
    }

    private Map<String, MenuEntity> findAllParent() {
        Map<String, MenuEntity> menuMap = new HashMap<>(); // menuId -> menuEntity
        Map<String, MenuEntity> parentMap = new HashMap<>(); //menuId -> parentEntity
        List<MenuEntity> menus = list();
        for (MenuEntity menu : menus) {
            String menuId = menu.getMenuId();
            String parentId = menu.getParentId();
            menuMap.put(menuId, menu);
            parentMap.put(menuId, menuMap.getOrDefault(parentId, null));
        }
        for (String menuId : parentMap.keySet()) {
            if (parentMap.get(menuId) == null) {
                parentMap.put(menuId, menuMap.getOrDefault(menuMap.get(menuId).getParentId(), null));
            }
        }
        return parentMap;
    }

    private List<MenuEntity> getChildren(String parentId, List<MenuEntity> menus){
        List<MenuEntity> children = new ArrayList<>();
        for(int i = 0; i < menus.size(); i++){
            if (parentId.equals(menus.get(i).getParentId())) {
                children.add(menus.get(i));
                menus.get(i).setChildren(getChildren(menus.get(i).getMenuId(), menus));
            }
        }
        return children.stream().sorted(Comparator.comparing(MenuEntity::getSeq)).collect(Collectors.toList());
    }

    //------以下是角色授权是构建的菜单树方法, 专用---------
    @Override
    public List<AuthMenuTree> findAuthMenu() {
        List<AuthMenuTree> tree = new ArrayList<>();
        List<MenuEntity> menus = list(new LambdaQueryWrapper<MenuEntity>().orderByAsc(MenuEntity::getSeq));
        for(int i = 0; i < menus.size(); i++){
            if (!StringUtils.hasText(menus.get(i).getParentId())){ //跟节点
                buildAuthTree(tree, menus, i);
            }
        }
        return tree;
    }
    private void buildAuthTree(List<AuthMenuTree> tree, List<MenuEntity> menus, int current) {
        MenuEntity menuEntity = menus.get(current);

        //当前menu的所有权限按钮
        List<MenuFuncEntity> funcKeys = menuFuncMapper.selectList(new LambdaQueryWrapper<MenuFuncEntity>()
                .eq(MenuFuncEntity::getMenuId, menuEntity.getMenuId())
                .orderByAsc(MenuFuncEntity::getSeq));

        //转换成树形结果实体
        AuthMenuTree menuTree = new AuthMenuTree(menuEntity);

        //添加权限
        if (funcKeys.size() > 0) {
            for (MenuFuncEntity fk : funcKeys) {
                AuthFuncKey authFuncKey = new AuthFuncKey();
                authFuncKey.setId(fk.getMenuId()+"#"+fk.getFuncKey());
                authFuncKey.setLabel(fk.getFuncName());
                menuTree.getFuncKeys().add(authFuncKey);
            }
        }

        //添加下级
        menuTree.setChildren(getAuthChildren(menuEntity.getMenuId(), menus));

        tree.add(menuTree);
    }
    private List<AuthMenuTree> getAuthChildren(String parentId, List<MenuEntity> menus){
        List<AuthMenuTree> tree = new ArrayList<>();
        for(int i = 0; i < menus.size(); i++){
            if (parentId.equals(menus.get(i).getParentId())) {
                buildAuthTree(tree, menus, i);
            }
        }
        return tree;
    }
    //--------end--------------------------------------
}
